using Microsoft.Phone.Controls.Primitives;
using Microsoft.Phone.Gestures;
using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace Microsoft.Phone.Controls
{
	[StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(PanoramaItem)), TemplatePart(Name = "BackgroundLayer", Type = typeof(PanningLayer)), TemplatePart(Name = "ItemsLayer", Type = typeof(PanningLayer)), TemplatePart(Name = "TitleLayer", Type = typeof(PanningLayer))]
	public class Panorama : TemplatedItemsControl<PanoramaItem>
	{
		internal const int Spacing = 48;
		internal const double PanningOpacity = 0.7;
		private const string BackgroundLayerElement = "BackgroundLayer";
		private const string TitleLayerElement = "TitleLayer";
		private const string ItemsLayerElement = "ItemsLayer";
		internal static readonly Duration Immediately = new Duration(TimeSpan.Zero);
		private static readonly Duration DefaultDuration = new Duration(TimeSpan.FromMilliseconds(800.0));
		private static readonly Duration EntranceDuration = Panorama.DefaultDuration;
		private static readonly Duration FlickDuration = Panorama.DefaultDuration;
		private static readonly Duration SnapDuration = Panorama.DefaultDuration;
		private static readonly Duration PanDuration = new Duration(TimeSpan.FromMilliseconds(150.0));
		private int _cumulativeDragDelta;
		private int _flickDirection;
		private int _targetOffset;
		private bool _dragged;
		private int _frameCount;
		private bool _updateBackgroundPending = true;
		private bool _entranceAnimationPlayed;
		private PanningLayer _panningBackground;
		private PanningLayer _panningTitle;
		private PanningLayer _panningItems;
		private bool _adjustSelectedRequested;
		private bool _suppressSelectionChangedEvent;
		private bool _loaded;
		private float previousBackgroundWidth;
		public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(object), typeof(Panorama), null);
		public static readonly DependencyProperty TitleTemplateProperty = DependencyProperty.Register("TitleTemplate", typeof(DataTemplate), typeof(Panorama), null);
		public static readonly DependencyProperty HeaderTemplateProperty = DependencyProperty.Register("HeaderTemplate", typeof(DataTemplate), typeof(Panorama), null);
		public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(Panorama), new PropertyMetadata(null, new PropertyChangedCallback(Panorama.OnSelectionChanged)));
		public static readonly DependencyProperty SelectedIndexProperty = DependencyProperty.Register("SelectedIndex", typeof(int), typeof(Panorama), new PropertyMetadata(-1));
		public static readonly DependencyProperty DefaultItemProperty = DependencyProperty.Register("DefaultItem", typeof(object), typeof(Panorama), new PropertyMetadata(null, new PropertyChangedCallback(Panorama.OnDefaultItemChanged)));
		private static readonly DependencyProperty BackgroundShadowProperty = DependencyProperty.Register("BackgroundShadow", typeof(Brush), typeof(Panorama), new PropertyMetadata(null, new PropertyChangedCallback(Panorama.OnBackgroundShadowChanged)));
		public event EventHandler<SelectionChangedEventArgs> SelectionChanged
		{
			[MethodImpl(32)]
			add
			{
				this.SelectionChanged = (EventHandler<SelectionChangedEventArgs>)Delegate.Combine(this.SelectionChanged, value);
			}
			[MethodImpl(32)]
			remove
			{
				this.SelectionChanged = (EventHandler<SelectionChangedEventArgs>)Delegate.Remove(this.SelectionChanged, value);
			}
		}
		internal PanoramaPanel Panel
		{
			get;
			set;
		}
		internal int ItemsWidth
		{
			get;
			set;
		}
		internal int ViewportWidth
		{
			get;
			private set;
		}
		internal int ViewportHeight
		{
			get;
			private set;
		}
		internal int AdjustedViewportWidth
		{
			get
			{
				return Math.Max(0, this.ViewportWidth - 48);
			}
		}
		public object Title
		{
			get
			{
				return base.GetValue(Panorama.TitleProperty);
			}
			set
			{
				base.SetValue(Panorama.TitleProperty, value);
			}
		}
		public DataTemplate TitleTemplate
		{
			get
			{
				return (DataTemplate)base.GetValue(Panorama.TitleTemplateProperty);
			}
			set
			{
				base.SetValue(Panorama.TitleTemplateProperty, value);
			}
		}
		public DataTemplate HeaderTemplate
		{
			get
			{
				return (DataTemplate)base.GetValue(Panorama.HeaderTemplateProperty);
			}
			set
			{
				base.SetValue(Panorama.HeaderTemplateProperty, value);
			}
		}
		public object SelectedItem
		{
			get
			{
				return base.GetValue(Panorama.SelectedItemProperty);
			}
			private set
			{
				base.SetValue(Panorama.SelectedItemProperty, value);
			}
		}
		public int SelectedIndex
		{
			get
			{
				return (int)base.GetValue(Panorama.SelectedIndexProperty);
			}
			private set
			{
				base.SetValue(Panorama.SelectedIndexProperty, value);
			}
		}
		public object DefaultItem
		{
			get
			{
				return base.GetValue(Panorama.DefaultItemProperty);
			}
			set
			{
				base.SetValue(Panorama.DefaultItemProperty, value);
				this.OnDefaultItemSet();
			}
		}
		internal PanoramaItem GetDefaultItemContainer()
		{
			return base.GetContainer(this.DefaultItem);
		}
		public Panorama()
		{
			PerfLog.BeginLogMarker(PerfMarkerEvents.MPC_PANO_STARTUP, PerfLog.Panorama);
			base.set_DefaultStyleKey(typeof(Panorama));
			GestureHelper gestureHelper = GestureHelper.Create(this, true);
			GestureHelper arg_4C_0 = gestureHelper;
			EventHandler<GestureEventArgs> value = delegate(object sender, GestureEventArgs e)
			{
				this.GestureStart(e);
			};
			arg_4C_0.GestureStart += value;
			GestureHelper arg_60_0 = gestureHelper;
			EventHandler<DragEventArgs> value2 = delegate(object sender, DragEventArgs e)
			{
				this.HorizontalDrag(e);
			};
			arg_60_0.HorizontalDrag += value2;
			GestureHelper arg_74_0 = gestureHelper;
			EventHandler<FlickEventArgs> value3 = delegate(object sender, FlickEventArgs e)
			{
				this.Flick(e);
			};
			arg_74_0.Flick += value3;
			GestureHelper arg_8A_0 = gestureHelper;
			EventHandler<EventArgs> value4 = delegate(object sender, EventArgs e)
			{
				this.GestureEnd();
			};
			arg_8A_0.GestureEnd += value4;
			base.add_SizeChanged(new SizeChangedEventHandler(this.OnSizeChanged));
			if (DesignerProperties.get_IsInDesignTool())
			{
				base.add_Loaded(new RoutedEventHandler(this.OnLoaded));
				base.add_Unloaded(new RoutedEventHandler(this.OnUnloaded));
			}
			else
			{
				CompositionTarget.add_Rendering(new EventHandler(this.EntranceAnimationCallback));
			}
			base.add_Loaded(new RoutedEventHandler(this.Panorama_Loaded));
		}
		private void Panorama_Loaded(object sender, RoutedEventArgs e)
		{
			base.remove_Loaded(new RoutedEventHandler(this.Panorama_Loaded));
			PerfLog.EndLogMarker(PerfMarkerEvents.MPC_PANO_STARTUP, PerfLog.Panorama);
		}
		private void OnLoaded(object sender, RoutedEventArgs e)
		{
			this._loaded = true;
		}
		private void OnUnloaded(object sender, RoutedEventArgs e)
		{
			this._loaded = false;
		}
		public override void OnApplyTemplate()
		{
			PerfLog.BeginLogMarker(PerfMarkerEvents.MPC_PANO_APPLYTEMPLATE, PerfLog.Panorama);
			base.OnApplyTemplate();
			this._panningBackground = (base.GetTemplateChild("BackgroundLayer") as PanningLayer);
			this._panningTitle = (base.GetTemplateChild("TitleLayer") as PanningLayer);
			this._panningItems = (base.GetTemplateChild("ItemsLayer") as PanningLayer);
			if (this._panningBackground != null)
			{
				this._panningBackground.Owner = this;
			}
			if (this._panningTitle != null)
			{
				this._panningTitle.Owner = this;
			}
			if (this._panningItems != null)
			{
				this._panningItems.Owner = this;
			}
			Binding binding = new Binding("Background");
			binding.set_RelativeSource(new RelativeSource(2));
			base.SetBinding(Panorama.BackgroundShadowProperty, binding);
			PerfLog.EndLogMarker(PerfMarkerEvents.MPC_PANO_APPLYTEMPLATE, PerfLog.Panorama);
		}
		protected override Size MeasureOverride(Size availableSize)
		{
			PerfLog.BeginLogMarker(PerfMarkerEvents.MPC_PANO_MEASURE, PerfLog.Panorama);
			if (Application.get_Current().get_Host().get_Content().get_ActualWidth() > 0.0)
			{
				this.ViewportWidth = (int)((!double.IsInfinity(availableSize.get_Width())) ? availableSize.get_Width() : Application.get_Current().get_Host().get_Content().get_ActualWidth());
				this.ViewportHeight = (int)((!double.IsInfinity(availableSize.get_Height())) ? availableSize.get_Height() : Application.get_Current().get_Host().get_Content().get_ActualHeight());
			}
			else
			{
				this.ViewportWidth = (int)Math.Min(availableSize.get_Width(), 480.0);
				this.ViewportHeight = (int)Math.Min(availableSize.get_Height(), 800.0);
			}
			base.MeasureOverride(new Size(double.PositiveInfinity, (double)this.ViewportHeight));
			if (double.IsInfinity(availableSize.get_Width()))
			{
				availableSize.set_Width((double)this.ViewportWidth);
			}
			if (double.IsInfinity(availableSize.get_Height()))
			{
				availableSize.set_Height((double)this.ViewportHeight);
			}
			PerfLog.EndLogMarker(PerfMarkerEvents.MPC_PANO_MEASURE, PerfLog.Panorama);
			return availableSize;
		}
		protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
		{
			base.OnItemsChanged(e);
			if (this.Panel != null)
			{
				this.Panel.ResetItemPositions();
			}
			this.RequestAdjustSelection();
		}
		internal void RequestAdjustSelection()
		{
			if (!this._adjustSelectedRequested)
			{
				base.add_LayoutUpdated(new EventHandler(this.LayoutUpdatedAdjustSelection));
				this._adjustSelectedRequested = true;
			}
		}
		private void LayoutUpdatedAdjustSelection(object sender, EventArgs e)
		{
			this._adjustSelectedRequested = false;
			base.remove_LayoutUpdated(new EventHandler(this.LayoutUpdatedAdjustSelection));
			this.AdjustSelection();
		}
		private void AdjustSelection()
		{
			if (!DesignerProperties.get_IsInDesignTool())
			{
				object selectedItem = this.SelectedItem;
				object obj = null;
				bool flag = false;
				bool flag2 = false;
				if (this.Panel != null && this.Panel.VisibleChildren.get_Count() > 0)
				{
					if (selectedItem == null)
					{
						obj = base.GetItem(this.Panel.VisibleChildren.get_Item(0));
					}
					else
					{
						PanoramaItem container = base.GetContainer(selectedItem);
						flag2 = this._entranceAnimationPlayed;
						if (container != null && this.Panel.VisibleChildren.Contains(container))
						{
							obj = selectedItem;
						}
						else
						{
							obj = base.GetItem(this.Panel.VisibleChildren.get_Item(0));
						}
					}
				}
				else
				{
					this._targetOffset = 0;
					this.GoTo(this._targetOffset, Panorama.Immediately);
				}
				if (flag)
				{
					this.SelectedItem = obj;
				}
				else
				{
					this.SetSelectionInternal(obj);
				}
				this.UpdateItemPositions();
				if (flag2)
				{
					PanoramaItem container2 = base.GetContainer(obj);
					if (container2 != null)
					{
						this._targetOffset = -container2.StartPosition;
						this.GoTo(this._targetOffset, Panorama.Immediately);
					}
				}
				return;
			}
			if (!this._loaded)
			{
				return;
			}
			this._targetOffset = 0;
			this.GoTo(this._targetOffset, Panorama.Immediately);
		}
		private void UpdateItemPositions()
		{
			bool flag = true;
			if (this.Panel != null)
			{
				if (this.Panel.VisibleChildren.get_Count() > 2 && this.SelectedItem != null)
				{
					PanoramaItem container = base.GetContainer(this.SelectedItem);
					if (container != null)
					{
						int num = this.Panel.VisibleChildren.IndexOf(container);
						if (num == this.Panel.VisibleChildren.get_Count() - 1)
						{
							this.Panel.ShowFirstItemOnRight();
							flag = false;
						}
						else
						{
							if (num == 0)
							{
								this.Panel.ShowLastItemOnLeft();
								flag = false;
							}
						}
					}
				}
				if (flag)
				{
					this.Panel.ResetItemPositions();
				}
			}
		}
		protected override Size ArrangeOverride(Size finalSize)
		{
			PerfLog.BeginLogMarker(PerfMarkerEvents.MPC_PANO_ARRANGE, PerfLog.Panorama);
			Size size = finalSize;
			size.set_Width(base.get_DesiredSize().get_Width());
			base.ArrangeOverride(finalSize);
			PerfLog.EndLogMarker(PerfMarkerEvents.MPC_PANO_ARRANGE, PerfLog.Panorama);
			return finalSize;
		}
		protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
		{
			base.PrepareContainerForItemOverride(element, item);
			PanoramaItem panoramaItem = element as PanoramaItem;
			if (panoramaItem != null)
			{
				if (panoramaItem.get_Content() == null && panoramaItem != item)
				{
					panoramaItem.set_Content(item);
				}
				if (panoramaItem.HeaderTemplate == null && element.ReadLocalValue(PanoramaItem.HeaderTemplateProperty) == DependencyProperty.UnsetValue)
				{
					panoramaItem.HeaderTemplate = this.HeaderTemplate;
				}
				if (panoramaItem.Header == null && !(item is UIElement) && panoramaItem.ReadLocalValue(PanoramaItem.HeaderProperty) == DependencyProperty.UnsetValue)
				{
					panoramaItem.Header = item;
				}
			}
		}
		private void GestureStart(GestureEventArgs args)
		{
			this._targetOffset = (int)this._panningItems.ActualOffset;
			this._flickDirection = 0;
			this._cumulativeDragDelta = 0;
			this._dragged = false;
		}
		private void HorizontalDrag(DragEventArgs args)
		{
			if (this._flickDirection == 0)
			{
				this._cumulativeDragDelta = (int)args.CumulativeDistance.get_X();
				this._targetOffset += (int)args.DeltaDistance.get_X();
				if (Math.Abs(this._cumulativeDragDelta) > this.ViewportWidth)
				{
					return;
				}
				this._dragged = true;
				this.GoTo(this._targetOffset, Panorama.PanDuration);
			}
		}
		private void Flick(FlickEventArgs e)
		{
			if (e.Angle == 180.0)
			{
				this._flickDirection = -1;
				return;
			}
			if (e.Angle == 0.0)
			{
				this._flickDirection = 1;
			}
		}
		private void GestureEnd()
		{
			if (this._flickDirection != 0)
			{
				this.ProcessFlick();
				return;
			}
			if (!this._dragged)
			{
				return;
			}
			int offset;
			int num;
			PanoramaItem container;
			bool flag;
			this.Panel.GetSnapOffset(this._targetOffset, this.ViewportWidth, Math.Sign(this._cumulativeDragDelta), out offset, out num, out container, out flag);
			if (flag)
			{
				this.WrapAround(Math.Sign(this._cumulativeDragDelta));
			}
			object item = base.GetItem(container);
			if (item != null)
			{
				this.SelectedItem = item;
			}
			this.UpdateItemPositions();
			this.GoTo(offset, Panorama.SnapDuration, delegate
			{
				this._panningItems.Refresh();
			});
		}
		private void ProcessFlick()
		{
			if (this._flickDirection == 0)
			{
				return;
			}
			int offset = (int)this._panningItems.ActualOffset;
			PanoramaPanel.ItemStop itemStop;
			PanoramaPanel.ItemStop itemStop2;
			PanoramaPanel.ItemStop itemStop3;
			this.Panel.GetStops(offset, this.ItemsWidth, out itemStop, out itemStop2, out itemStop3);
			if (itemStop == itemStop2 && itemStop2 == itemStop3 && itemStop3 == null)
			{
				return;
			}
			this._targetOffset = ((this._flickDirection < 0) ? (-itemStop3.Position) : (-itemStop.Position));
			if (Math.Sign((double)this._targetOffset - this._panningItems.ActualOffset) != Math.Sign(this._flickDirection))
			{
				this.WrapAround(Math.Sign(this._flickDirection));
			}
			this.SelectedItem = base.GetItem((this._flickDirection < 0) ? itemStop3.Item : itemStop.Item);
			this.UpdateItemPositions();
			this.GoTo(this._targetOffset, Panorama.FlickDuration, delegate
			{
				this._panningItems.Refresh();
			});
		}
		private void GoTo(int offset, Duration duration, Action completionAction)
		{
			if (this._panningBackground != null)
			{
				this._panningBackground.GoTo(offset, duration, null);
			}
			if (this._panningTitle != null)
			{
				this._panningTitle.GoTo(offset, duration, null);
			}
			if (this._panningItems != null)
			{
				this._panningItems.GoTo(offset, duration, completionAction);
			}
		}
		private void GoTo(int offset)
		{
			this.GoTo(offset, null);
		}
		private void GoTo(int offset, Action completionAction)
		{
			int num = Math.Abs((int)this._panningItems.ActualOffset - offset);
			this.GoTo(offset, TimeSpan.FromMilliseconds((double)(num * 2)), completionAction);
		}
		private void GoTo(int offset, Duration duration)
		{
			this.GoTo(offset, duration, null);
		}
		private void WrapAround(int direction)
		{
			this._panningBackground.Wraparound(direction);
			this._panningTitle.Wraparound(direction);
			this._panningItems.Wraparound(direction);
		}
		private void SetSelectionInternal(object selectedItem)
		{
			this._suppressSelectionChangedEvent = true;
			this.SelectedItem = selectedItem;
			this._suppressSelectionChangedEvent = false;
		}
		private static void OnSelectionChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
		{
			Panorama panorama = obj as Panorama;
			if (panorama != null)
			{
				panorama.SelectedIndex = panorama.get_Items().IndexOf(args.get_NewValue());
				if (!panorama._suppressSelectionChangedEvent && panorama.get_Items().Contains(args.get_NewValue()))
				{
					SafeRaise.Raise<SelectionChangedEventArgs>(panorama.SelectionChanged, panorama, () => new SelectionChangedEventArgs((args.get_OldValue() == null) ? new object[0] : new object[]
					{
						args.get_OldValue()
					}, (args.get_NewValue() == null) ? new object[0] : new object[]
					{
						args.get_NewValue()
					}));
				}
			}
		}
		private static void OnDefaultItemChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
		{
			((Panorama)obj).OnDefaultItemSet();
		}
		private void OnDefaultItemSet()
		{
			if (this.Panel != null)
			{
				this.Panel.NotifyDefaultItemChanged();
				if (this.Panel.VisibleChildren.get_Count() > 0)
				{
					this.SelectedItem = this.DefaultItem;
				}
				if (this.Panel != null)
				{
					this.Panel.ResetItemPositions();
				}
				this._panningItems.Refresh();
				this.UpdateItemPositions();
				this.GoTo(0, Panorama.Immediately);
			}
		}
		private static void OnBackgroundShadowChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
		{
			Panorama panorama = (Panorama)obj;
			if (!panorama._updateBackgroundPending)
			{
				panorama.UpdateBackground();
			}
		}
		private void UpdateBackground()
		{
			this._updateBackgroundPending = false;
			this._panningBackground.ContentPresenter.set_Height((double)this.ViewportHeight);
			if (base.get_Background() is SolidColorBrush)
			{
				this._panningBackground.ContentPresenter.set_Width((double)this.ViewportWidth);
				this._panningBackground.IsStatic = true;
				return;
			}
			if (base.get_Background() is GradientBrush)
			{
				this._panningBackground.ContentPresenter.set_Width((double)Math.Max(this.ItemsWidth, this.ViewportWidth));
				this._panningBackground.IsStatic = (this._panningBackground.ContentPresenter.get_Width() == (double)this.ViewportWidth);
				return;
			}
			if (base.get_Background() is ImageBrush)
			{
				ImageBrush imageBrush = (ImageBrush)base.get_Background();
				BitmapImage bmp = imageBrush.get_ImageSource() as BitmapImage;
				if (this._panningBackground.ContentPresenter != null && bmp != null)
				{
					if (!string.IsNullOrEmpty(bmp.get_UriSource().get_OriginalString()))
					{
						if (bmp.get_PixelWidth() == 0)
						{
							bmp.remove_ImageOpened(new EventHandler<RoutedEventArgs>(this.OnBackgroundImageOpened));
							bmp.add_ImageOpened(new EventHandler<RoutedEventArgs>(this.OnBackgroundImageOpened));
							base.get_Dispatcher().BeginInvoke(delegate
							{
								this.AsyncUpdateBackground(bmp);
							});
						}
						this._panningBackground.ContentPresenter.set_Width((double)bmp.get_PixelWidth());
						if (this.previousBackgroundWidth == (float)bmp.get_PixelWidth() || bmp.get_PixelHeight() >= this.ViewportHeight)
						{
							this._panningBackground.Refresh();
						}
						this.previousBackgroundWidth = (float)bmp.get_PixelWidth();
					}
					else
					{
						this._panningBackground.Refresh();
					}
				}
				this._panningBackground.IsStatic = false;
			}
		}
		private void OnBackgroundImageOpened(object sender, RoutedEventArgs e)
		{
			this.AsyncUpdateBackground((BitmapImage)sender);
		}
		private void AsyncUpdateBackground(BitmapImage img)
		{
			img.remove_ImageOpened(new EventHandler<RoutedEventArgs>(this.OnBackgroundImageOpened));
			this.UpdateBackground();
		}
		private void OnSizeChanged(object sender, SizeChangedEventArgs e)
		{
			this.ViewportWidth = (int)e.get_NewSize().get_Width();
			this.ViewportHeight = (int)e.get_NewSize().get_Height();
			this.ItemsWidth = (int)this.Panel.get_ActualWidth();
			this.UpdateBackground();
			RectangleGeometry rectangleGeometry = new RectangleGeometry();
			rectangleGeometry.set_Rect(new Rect(0.0, 0.0, e.get_NewSize().get_Width(), e.get_NewSize().get_Height()));
			base.set_Clip(rectangleGeometry);
		}
		private void EntranceAnimationCallback(object sender, EventArgs e)
		{
			switch (this._frameCount++)
			{
			case 0:
				this.GoTo(this.ViewportWidth, Panorama.Immediately);
				return;
			case 1:
				this.GoTo(0, Panorama.EntranceDuration);
				this._entranceAnimationPlayed = true;
				CompositionTarget.remove_Rendering(new EventHandler(this.EntranceAnimationCallback));
				return;
			default:
				return;
			}
		}
	}
}
